﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using SdmxMl.Common;
using SdmxMl.Helper;
using System.Windows.Forms;
using System.Data;

namespace SdmxMl.Structure
{
    /// <summary>
    /// The report structure describes the presentation of the reported concepts,
    /// and associates them with target identifiers, full or partial. It can be
    /// given a name and/or annotations. It must be given an ID, using the id
    /// attribute, which must be unique within the MetadataStructureDefinition
    /// element. It contains one or more MetadataAttribute elements, each of which
    /// may either hold a value, or may have subordinate MetadataAttribute elements.
    /// The target attribute holds the ID of a full or partial identifier, which is
    /// the identifier of the target against which the metadata attributes are reported.
    /// </summary>
    public class ReportStructureType : BaseArtefact
    {
        #region Properties

        private string _urn;
        public string Urn
        {
            get { return _urn; }
            set { _urn = value; }
        }

        private string _uri;
        public string Uri
        {
            get { return _uri; }
            set { _uri = value; }
        }

        // SDMX 2.0 has only one target
        public string TargetId
        {
            get { return TargetIdList[0]; }
            set { TargetIdList[0] = value; }
        }

        // SDMX 2,1 can have many targets
        private List<string> _targetIdList;
        public List<string> TargetIdList { get { return _targetIdList; } }
        


        private MetadataAttributeTypeList _metadataAttributeList;
        public MetadataAttributeTypeList MetadataAttributeList
        {
            get { return _metadataAttributeList; }
        }

        // The Parent MSD object
        private MetadataStructureDefinitionType _msd;
        public MetadataStructureDefinitionType Msd
        {
            get { return _msd; }
        }


        #endregion //Properties

        #region Constructors

        private void Init()
        {
            _metadataAttributeList = new MetadataAttributeTypeList();

            _targetIdList = new List<string>();
        }

        public ReportStructureType(MetadataStructureDefinitionType msd)
        {
            _msd = msd;
            Init();
            _targetIdList.Add(string.Empty);

        }
        public ReportStructureType(MetadataStructureDefinitionType msd, XmlNode nodeArtefact, SdmxNamespaceManager nsmgr) 
            : base(nodeArtefact, nsmgr)
        {
            _msd = msd;
            Init();
            _urn = Xmlhelper.GetAtt(nodeArtefact, "urn");
            _uri = Xmlhelper.GetAtt(nodeArtefact, "uri");

            _targetIdList.Add(Xmlhelper.GetAtt(nodeArtefact, "target"));

            string query = string.Format("./structure:MetadataAttribute");
            XmlNodeList nodeList = nodeArtefact.SelectNodes(query, nsmgr);
            if (nodeList.Count > 0)
            {
                foreach (XmlNode nd in nodeList)
                {
                    MetadataAttributeType meta = new MetadataAttributeType(nd, nsmgr);
                    _metadataAttributeList.Add(meta);
                }
            }
            else
            {
                throw new ApplicationException("Unexpected, no MetadataAttribute in " + Id);
            }

            if (nsmgr.VersionSdmx != SdmxVersion.SDMX_20)
            {

                // Target list
                _targetIdList.Clear();
                query = "./structure:MetadataTarget/Ref";
                nodeList = nodeArtefact.SelectNodes(query, nsmgr);
                foreach (XmlNode nd in nodeList)
                    _targetIdList.Add(Xmlhelper.GetAtt(nd, "id"));
            }

        
        }

        #endregion // Constructors

        #region XML serialize
        
        public void WriteXml(XmlTextWriter xw, string prefix, string tag)
        {
            xw.WriteStartElement(prefix, tag, null);

            // value required
            xw.WriteAttributeString("id", Id);
            Xmlhelper.WriteAttributeIfExist(xw, "urn", Urn);
            Xmlhelper.WriteAttributeIfExist(xw, "uri", Uri);

            if (SdmxNamespaceManager.SdmxTarget == SdmxVersion.SDMX_20)
            {

                // value required
                xw.WriteAttributeString("target", TargetId);

                Name.WriteXml(xw, prefix, "Name");
                Description.WriteXml(xw, prefix, "Description");

                foreach (MetadataAttributeType meta in _metadataAttributeList)
                    meta.WriteXml(xw, prefix, "MetadataAttribute");

                // Annotations
                AnnotationList.WriteXml(xw, prefix, null);
            }
            else // 2.1
            {
                AnnotationList.WriteXml(xw, "common", null);
                foreach (MetadataAttributeType meta in _metadataAttributeList)
                    meta.WriteXml(xw, prefix, "MetadataAttribute");
                // Target 
                xw.WriteStartElement(prefix, "MetadataTarget", null);
                xw.WriteStartElement("Ref");
                xw.WriteAttributeString("id", TargetId);
                xw.WriteEndElement();
                xw.WriteEndElement();

            }

            xw.WriteEndElement();
        }

        #endregion // XML serialize

        #region Tree

        public override TreeNode FillNode(TreeNode parentNode)
        {
            TreeNode t = base.FillNode(parentNode);

            return t;
        }
        #endregion //Tree

        #region String Representation

        public override string ToString()
        {
            string txt = Id;
            if (Name.ToString() != MultiLang.UndefinedText)
                txt += " - " + Name.ToString();
            return txt;
        }
        #endregion // String Representation

    }

    public class ReportStructureTypeList : List<ReportStructureType>, ISdmxNewChild, ISdmxDelChild
    {
        private MetadataStructureDefinitionType _msd;
        public ReportStructureTypeList(MetadataStructureDefinitionType msd)
        {
            _msd = msd;
        }

        public ReportStructureType LocateItem(string itemId)
        {
            ReportStructureType ret = null;
            foreach (ReportStructureType item in this)
                if (item.Id == itemId)
                {
                    ret = item;
                    break;
                }
            return ret;
        }
        /// <summary>Create table container object</summary>
        /// <returns>The dataTable object</returns>
        private DataTable CreateTableContainer()
        {
            //"Code", "Description"
            DataTable dataTable = new DataTable();
            dataTable.Columns.Add(new DataColumn("ReportRef", typeof(string)));
            dataTable.Columns.Add(new DataColumn("Description", typeof(string)));
            dataTable.Columns.Add(new DataColumn("Target Id", typeof(string)));

            return dataTable;
        }

        public DataTable GetTableRepresentation()
        {
            DataTable dataTable = CreateTableContainer();
            foreach (ReportStructureType art in this)
                dataTable.Rows.Add(new object[] { art.Id, art.Version + " - " + art.Name.ToString(), art.TargetId });

            return dataTable;
        }

        #region ISdmxNewChild Members

        public TreeNode NewChild(TreeNode node)
        {
            string undefId = "Undefined";

            ReportStructureType rpt = new ReportStructureType(_msd);
            rpt.Id = undefId;
            MetadataAttributeType metaNew = new MetadataAttributeType();
            metaNew.ConceptInfo.Id = undefId;
            rpt.MetadataAttributeList.Add(metaNew);

            Add(rpt);
            TreeNode t = rpt.FillNode(node);
            return t;
        }

        public void DelChild(object o)
        {
            ReportStructureType rpt = o as ReportStructureType;
            if (rpt != null && Contains(rpt))
                Remove(rpt);
        }

        #endregion

        public override string ToString()
        {
            return "Reports";
        }

    }
}
